package com.tools.util;


import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;

import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

/**
 * Utils - RSA加密解密
 *
 * 依赖于apache_commons包
 * @author zhaoqiang
 * @version 1.0
 */
public final class RSAUtils {

    private static Cipher cipher;
    private static String encoding = "UTF-8";

    static {
        try {
            cipher = Cipher.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成密钥对
     *
     * @param pubkeyfile
     * @param privatekeyfile
     * @throws NoSuchAlgorithmException
     * @throws IOException
     */
    public static void makeKeyFile(String pubkeyfile, String privatekeyfile)
            throws NoSuchAlgorithmException, IOException {
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器，密钥大小为1024位
        keyPairGen.initialize(1024);
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // 生成私钥
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
                privatekeyfile));
        oos.writeObject(privateKey);
        oos.flush();
        oos.close();
        oos = new ObjectOutputStream(new FileOutputStream(pubkeyfile));
        oos.writeObject(publicKey);
        oos.flush();
        oos.close();
    }

    /**
     * 加密算法
     * @param keyPath
     * @param text
     * @return
     * @throws Exception
     */
    public static String encrypt(String keyPath,String text){
        Key key = getRSAKey(keyPath);
        try {
            return encrypt(key,text);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 加密算法
     *
     * @param k
     * @param text
     * @return
     * @throws Exception
     */
    public static String encrypt(Key k, String text){
        try {
            return encrypt(k, text.getBytes(encoding));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

	/**
	 * 加密
	 * 
	 * @param publicKey
	 *            公钥
	 * @param text
	 *            字符串
	 * 
	 * @return Base64编码字符串
	 */
	public static String encrypt(PublicKey publicKey, String text) {
		return encrypt(publicKey, text.getBytes());
	}

    /**
     * 加密算法
     *
     * @param k
     * @param text
     * @return
     * @throws Exception
     */
    public static String encrypt(Key k, byte[] text) {
        if (cipher == null || k==null) {
            return null;
        }
        String str=null;
        try {
            cipher.init(Cipher.ENCRYPT_MODE, k);
            byte[] resultBytes = cipher.doFinal(text);
            str= Base64.encodeBase64String(resultBytes);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }finally {
            return str;
        }
    }

    /**
     * 解密算法
     *
     * @param keyPath
     * @param text
     * @return
     * @throws Exception
     */
    public static String decrypt(String keyPath, String text) {
        Key key = getRSAKey(keyPath);
        try {
            return decrypt(key,text);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 解密算法
     *
     * @param k
     * @param text
     * @return
     */
    public static String decrypt(Key k, String text){
        String str="";
        if(cipher ==null || k==null){
            return null;
        }
        try {
            cipher.init(Cipher.DECRYPT_MODE, k);
            byte[] resultBytes = cipher.doFinal(Base64.decodeBase64(text));
            str= new String(resultBytes, encoding);
        } catch (InvalidKeyException | IllegalBlockSizeException | UnsupportedEncodingException | BadPaddingException e) {
            e.printStackTrace();
        } finally {
            return str;
        }
    }

    /**
     * 获取Key
     * @param path
     * @return
     */
    public static Key getRSAKey(String path) {
        Key prikey =null;
        try {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
            prikey = (Key) ois.readObject();
            ois.close();
            return prikey;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            return prikey;
        }
    }
}